#include <QtGui>
#include "helpers.h"
#include "myeeprom.h"



QString getSWName(int val)
{

    if(!val) return "---";
    if(val==(NUM_SWITCHES+1)) return "ON";
    if(val==-(NUM_SWITCHES+1)) return "OFF";

    return QString(val<0 ? "!" : "") + QString(SWITCHES_STR).mid((abs(val)-1)*3,3);
}

void populateSwitchCB(QComboBox *b, int value=0)
{
    b->clear();
    for(int i=-(NUM_SWITCHES+1); i<=(NUM_SWITCHES+1); i++)
        b->addItem(getSWName(i));
    b->setCurrentIndex(value+NUM_SWITCHES+1);
    b->setMaxVisibleItems(10);
}

void populateCurvesCB(QComboBox *b, int value)
{
    QString str = CURV_STR;
    b->clear();
    for(int i=0; i<(str.length()/3); i++)  b->addItem(str.mid(i*3,3).replace("c","Curve "));
    b->setCurrentIndex(value);
    b->setMaxVisibleItems(10);
}

QString getDestStr(int idx)
{
    if(idx>MAX_KPID)
        return QString("CHN%1").arg(idx-MAX_KPID,2,10,QChar('0'));
    else
        return QString("PID%1").arg(idx,2,10,QChar('0'));
}

QString getSourceStr(int typ)
{
    QString st = "----";
    switch (typ)
    {
    case (SRC_TYPE_CMD):
        st = "CMD";
        break;
    case (SRC_TYPE_PID):
        st = "PID";
        break;
    case (SRC_TYPE_CHN):
        st = "CHN";
        break;
    case (SRC_TYPE_GYRO):
        st = "GYRO";
        break;
    case (SRC_TYPE_ACCEL):
        st = "ACCEL";
        break;
    case (SRC_TYPE_MAG):
        st = "MAG";
        break;
    case (SRC_TYPE_BARO):
        st = "BARO";
        break;
    case (SRC_TYPE_ATTITUDE):
        st = "ATTITUDE";
        break;
    case (SRC_TYPE_AP):
        st = "AP";
        break;
    default:
        st = "----";
        break;
    };

    return st;
}

void populateSourceCB(QComboBox *b, int value)
{
    b->clear();
    for(int i=0; i<=SRC_TYPE_COUNT; i++) b->addItem(getSourceStr(i));
    b->setCurrentIndex(value);
    b->setMaxVisibleItems(10);
}


QString getCSWFunc(int val)
{
    return QString(CSWITCH_STR).mid(val*CSW_LEN_FUNC,CSW_LEN_FUNC);
}


void populateCSWCB(QComboBox *b, int value)
{
    b->clear();
    for(int i=0; i<CSW_NUM_FUNC; i++) b->addItem(getCSWFunc(i));
    b->setCurrentIndex(value);
    b->setMaxVisibleItems(10);
}

int getValueFromLine(const QString &line, int pos, int len=2)
{
    bool ok;
    int hex = line.mid(pos,len).toInt(&ok, 16);
    return ok ? hex : -1;
}

QString iHEXLine(quint8 * data, quint16 addr, quint8 len)
{
    QString str = QString(":%1%2000").arg(len,2,16,QChar('0')).arg(addr,4,16,QChar('0')); //write start, bytecount (32), address and record type
    quint8 chkSum = 0;
    chkSum = -len; //-bytecount; recordtype is zero
    chkSum -= addr & 0xFF;
    chkSum -= addr >> 8;
    for(int j=0; j<len; j++)
    {
        str += QString("%1").arg(data[addr+j],2,16,QChar('0'));
        chkSum -= data[addr+j];
    }

    str += QString("%1").arg(chkSum,2,16,QChar('0'));
    return str.toUpper(); // output to file and lf;
}

int loadiHEX(QWidget *parent, QString fileName, quint8 * data, int datalen, QString header)
{
    //load from intel hex type file
    QFile file(fileName);
    int finalSize = 0;

    if(!file.exists())
    {
        QMessageBox::critical(parent, QObject::tr("Error"),QObject::tr("Unable to find file %1!").arg(fileName));
        return 0;
    }

    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {  //reading HEX TEXT file
        QMessageBox::critical(parent, QObject::tr("Error"),
                              QObject::tr("Error opening file %1:\n%2.")
                              .arg(fileName)
                              .arg(file.errorString()));
        return 0;
    }

    memset(data,0,datalen);

    QTextStream in(&file);

    if(!header.isEmpty())
    {
        QString hline = in.readLine();

        if(hline!=header)
        {
            QMessageBox::critical(parent, QObject::tr("Error"),
                                  QObject::tr("Invalid pipo File Format %1")
                                  .arg(fileName));
            file.close();
            return 0;
        }
    }

    while (!in.atEnd())
    {
        QString line = in.readLine();

        if(line.left(1)!=":") continue;

        int byteCount = getValueFromLine(line,1);
        int address = getValueFromLine(line,3,4);
        int recType = getValueFromLine(line,7);

        if(byteCount<0 || address<0 || recType<0)
        {
            QMessageBox::critical(parent, QObject::tr("Error"),QObject::tr("Error reading file %1!").arg(fileName));
            file.close();
            return 0;
        }

        QByteArray ba;
        ba.clear();

        quint8 chkSum = 0;
        chkSum -= byteCount;
        chkSum -= recType;
        chkSum -= address & 0xFF;
        chkSum -= address >> 8;
        for(int i=0; i<byteCount; i++)
        {
            quint8 v = getValueFromLine(line,(i*2)+9) & 0xFF;
            chkSum -= v;
            ba.append(v);
        }


        quint8 retV = getValueFromLine(line,(byteCount*2)+9) & 0xFF;
        if(chkSum!=retV) {
            QMessageBox::critical(parent, QObject::tr("Error"),QObject::tr("Checksum Error reading file %1!").arg(fileName));
            file.close();
            return 0;
        }

        if((recType == 0x00) && ((address+byteCount)<=datalen)) //data record - ba holds record
        {
            memcpy(&data[address],ba.data(),byteCount);
            finalSize += byteCount;
        }

    }

    file.close();
    return finalSize;
}

bool saveiHEX(QWidget *parent, QString fileName, quint8 * data, int datalen, QString header)
{
    QFile file(fileName);


    //open file
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
        QMessageBox::warning(parent, QObject::tr("Error"),
                             QObject::tr("Cannot write file %1:\n%2.")
                             .arg(fileName)
                             .arg(file.errorString()));
        return false;
    }

    QTextStream out(&file);

    //write file header in Intel HEX format
    if(!header.isEmpty())
    {
        out << header << "\n";
    }

    int addr = 0;
//    if(notesIndex>0)
//        addr =0;

    while (addr<datalen)
    {
        int llen = 32;
        if((datalen-addr)<llen)
            llen = datalen-addr;

        out << iHEXLine(data, addr, llen) << "\n";

        addr += llen;
    }

    out << ":00000001FF";  // write EOF

    file.close();

    return true;
}




void appendTextElement(QDomDocument * qdoc, QDomElement * pe, QString name, QString value)
{
    QDomElement e = qdoc->createElement(name);
    QDomText t = qdoc->createTextNode(name);
    t.setNodeValue(value);
    e.appendChild(t);
    pe->appendChild(e);
}

void appendNumberElement(QDomDocument * qdoc, QDomElement * pe,QString name, int value, bool forceZeroWrite)
{
    if(value || forceZeroWrite)
    {
        QDomElement e = qdoc->createElement(name);
        QDomText t = qdoc->createTextNode(name);
        t.setNodeValue(QString("%1").arg(value));
        e.appendChild(t);
        pe->appendChild(e);
    }
}

void appendCDATAElement(QDomDocument * qdoc, QDomElement * pe,QString name, const char * data, int size)
{
        QDomElement e = qdoc->createElement(name);
        QDomCDATASection t = qdoc->createCDATASection(name);
        t.setData(QByteArray(data, size).toBase64());
        e.appendChild(t);
        pe->appendChild(e);
}

QDomElement getModelDataXML(QDomDocument * qdoc, EEPROMData * tgen)
{
    QDomElement gd = qdoc->createElement("PIPO_DATA");

    appendNumberElement(qdoc, &gd, "Version", tgen->mdvers, true); // have to write value here
//    appendTextElement(qdoc, &gd, "Owner", QString::fromAscii(tgen->ownerName,sizeof(tgen->ownerName)).trimmed());
    appendCDATAElement(qdoc, &gd, "Data", (const char *)tgen,sizeof(EEPROMData));
    return gd;

}






bool loadModelDataXML(QDomDocument * qdoc, EEPROMData * tgen)
{
    //look for "GENERAL_DATA" tag
    QDomElement gde = qdoc->elementsByTagName("PIPO_DATA").at(0).toElement();

    if(gde.isNull()) // couldn't find
        return false;

    //load cdata into tgen
    QDomNode n = gde.elementsByTagName("Data").at(0).firstChild();// get all children in Data
    while (!n.isNull())
    {
        if (n.isCDATASection())
        {
            QString ds = n.toCDATASection().data();
            QByteArray ba = QByteArray::fromBase64(ds.toAscii());
            const char * data = ba.data();
            memcpy(tgen, data, sizeof(EEPROMData));
            break;
        }
        n = n.nextSibling();
    }

    //check version?

    return true;
}


